package com.hy.service.Impl;


import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hy.common.Result.ResponseEnum;
import com.hy.common.baseEnum.OrderStateEnum;
import com.hy.common.entity.Order;
import com.hy.common.exception.StandardException;
import com.hy.common.vo.OrderVo;
import com.hy.mapper.OrderMapper;
import com.hy.service.OrderService;
import com.hy.service.envent.PaymentSuccessEvent;
import com.hy.utils.DateUtils;
import com.hy.utils.OrderUtils;
import com.hy.utils.aliResponse.AliTradeStatusUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;


/**
 * 订单服务实现类
 *
 * @author 王富贵
 * @since 2022-04-19
 */
@Service
@Slf4j
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements OrderService {
    @Resource
    private OrderMapper orderMapper;

    @Resource
    private ApplicationEventPublisher applicationEventPublisher;

    /**
     * 添加一个支付宝订单
     *
     * @param outTradeNo 商户订单号
     * @param amount     支付金额
     * @return true 插入成功 | false 插入失败
     */
    @Override
    public boolean putAliOrder(Long outTradeNo, String amount) {
        // 防止幂等性问题，查询是否存在订单
        Order queryOrder = orderMapper.selectOne(new LambdaQueryWrapper<Order>()
                .eq(Order::getOutTradeNo, outTradeNo));
        if (Objects.nonNull(queryOrder)) {
            return false;
        }
        Order order = new Order(outTradeNo, amount, OrderStateEnum.订单支付中(), "支付宝");
        //创建并插入一个订单
        orderMapper.insert(order);
        return true;
    }

    /**
     * 根据订单号修改为订单状态为已支付
     *
     * @param outTradeNo 订单号
     */
    @Override
    @Transactional(rollbackFor = Exception.class ,propagation = Propagation.REQUIRED)
    public void orderPaid(Long outTradeNo) {
        Order order = orderMapper.selectOne(new LambdaQueryWrapper<Order>()
                .eq(Order::getOutTradeNo, outTradeNo));
        //如果订单号不存在
        if (Objects.isNull(order)) {
            log.error(ResponseEnum.A_LI_ORDER_DOES_NOT_EXIST.getMessage());
            throw new StandardException(ResponseEnum.A_LI_ORDER_DOES_NOT_EXIST);
            // TODO 回调接口查询的订单号不存在，可能存在bug
        }
        //如果存在并且为支付状态，幂等性问题
        if (order.getState() == OrderStateEnum.订单支付成功()) {
            log.warn("出现重复确认支付情况");
        }
        //修改状态
        order.setState(OrderStateEnum.订单支付成功());
        orderMapper.update(order, new LambdaQueryWrapper<Order>().eq(Order::getOutTradeNo, outTradeNo));
        log.info("订单{}支付成功", outTradeNo);

        //TODO 接受到支付成功的后续操作
        applicationEventPublisher.publishEvent(new PaymentSuccessEvent(order));
    }

    /**
     * 订单状态修改为已撤销
     *
     * @param outTradeNo 订单号
     */
    @Override
    public void orderCancel(Long outTradeNo) {
        Order order = orderMapper.selectOne(new LambdaQueryWrapper<Order>()
                .eq(Order::getOutTradeNo, outTradeNo));
        //如果订单号不存在
        if (Objects.isNull(order)) {
            log.error(ResponseEnum.A_LI_ORDER_DOES_NOT_EXIST.getMessage());
            throw new StandardException(ResponseEnum.A_LI_ORDER_DOES_NOT_EXIST);
        }
        //只有在订单状态合法情况下才执行方法
        Integer orderState = order.getState();
        if (orderState == OrderStateEnum.订单支付中() || orderState == OrderStateEnum.订单生成()) {
            order.setState(OrderStateEnum.订单已撤销());
            orderMapper.update(order, new LambdaQueryWrapper<Order>().eq(Order::getOutTradeNo, outTradeNo));
            return;
        }
        //其他情况都是当前订单状态不合法
        throw new StandardException(ResponseEnum.ORDER_STATUS_IS_INVALID);
    }

    /**
     * 订单状态设置为已退款
     *
     * @param outTradeNo 订单号
     */
    @Override
    public void OrderRefunded(Long outTradeNo) {
        Order order = orderMapper.selectOne(new LambdaQueryWrapper<Order>()
                .eq(Order::getOutTradeNo, outTradeNo));
        //如果订单号不存在
        if (Objects.isNull(order)) {
            log.error(ResponseEnum.A_LI_ORDER_DOES_NOT_EXIST.getMessage());
            throw new StandardException(ResponseEnum.A_LI_ORDER_DOES_NOT_EXIST);
        }
        //只有在订单状态合法情况下才执行方法
        Integer orderState = order.getState();
        if (orderState == OrderStateEnum.订单支付成功()) {
            order.setState(OrderStateEnum.订单已退款());
            orderMapper.update(order, new LambdaQueryWrapper<Order>().eq(Order::getOutTradeNo, outTradeNo));
            return;
        }
        //其他情况都是当前订单状态不合法
        throw new StandardException(ResponseEnum.ORDER_STATUS_IS_INVALID);
    }

    /**
     * 订单状态设置为订单关闭
     *
     * @param outTradeNo 订单号
     */
    @Override
    public void orderClosed(Long outTradeNo) {
        Order order = orderMapper.selectOne(new LambdaQueryWrapper<Order>()
                .eq(Order::getOutTradeNo, outTradeNo));
        //如果订单号不存在
        if (Objects.isNull(order)) {
            log.error(ResponseEnum.A_LI_ORDER_DOES_NOT_EXIST.getMessage());
            throw new StandardException(ResponseEnum.A_LI_ORDER_DOES_NOT_EXIST);
        }
        order.setState(OrderStateEnum.订单关闭());
        orderMapper.update(order, new LambdaQueryWrapper<Order>().eq(Order::getOutTradeNo, outTradeNo));
    }

    /**
     * 根据订单号查询当前订单状态
     *
     * @param outTradeNo 订单号
     * @return String 订单状态
     */
    @Override
    public String getOrderState(Long outTradeNo) {
        Order order = orderMapper.selectOne(new LambdaQueryWrapper<Order>()
                .eq(Order::getOutTradeNo, outTradeNo));
        //如果订单号不存在
        if (Objects.isNull(order)) {
            log.error(ResponseEnum.A_LI_ORDER_DOES_NOT_EXIST.getMessage());
            throw new StandardException(ResponseEnum.A_LI_ORDER_DOES_NOT_EXIST);
        }
        return OrderUtils.getOrderState(order.getState());
    }

    /**
     * 获取订单分页数据
     *
     * @param current 当前页数
     * @param size    页面大小
     * @return 订单集合
     */
    @Override
    public Page<OrderVo> getPageOrderList(Integer current, Integer size) {
        if (Objects.isNull(current) || Objects.isNull(size)) {
            throw new StandardException(ResponseEnum.PARAMETER_IS_EMPTY);
        }
        Page<Order> orderPage = new Page<>(current, size);
        LambdaQueryWrapper<Order> wrapper = new LambdaQueryWrapper<Order>()
                .orderByDesc(Order::getCreatedTime);
        Page<Order> result = orderMapper.selectPage(orderPage, wrapper);
        //获取集合数据
        List<Order> records = result.getRecords();
        //如果数据为空
        if (records.size() == 0) {
            return null;
        }

        //如果不为空，转化为vo数据
        List<OrderVo> orderVos = records
                .parallelStream()
                .map(order -> {
                    //将对象转化为vo对象
                    OrderVo orderVo = new OrderVo();
                    BeanUtils.copyProperties(order, orderVo);
                    //对状态的转化
                    orderVo.setState(OrderUtils.getOrderState(order.getState()));
                    //对时间的转换
                    orderVo.setCreatedTime(DateUtils.convertDate(order.getCreatedTime()));
                    return orderVo;
                })
                .collect(Collectors.toList());

        Page<OrderVo> orderVoPage = new Page<>(current, size);
        BeanUtils.copyProperties(result, orderVoPage);
        return orderVoPage.setRecords(orderVos);
    }

    /**
     * 数据库同步与远端订单状态
     * 异步同步
     *
     * @param tradeStatus  支付宝订单状态str
     * @param out_trade_no 商户订单号
     */
    @Override
    @Async("UpdateAndSendExecutor")
    public void syncOrderStatus(String tradeStatus, String out_trade_no) {
        //查出该订单
        Order order = orderMapper.selectOne(new LambdaQueryWrapper<Order>()
                .eq(Order::getOutTradeNo, out_trade_no));
        //订单判空
        if (Objects.isNull(order)) {
            throw new StandardException(ResponseEnum.A_LI_ORDER_DOES_NOT_EXIST);
        }

        //获取远端支付状态
        Integer queryOrderState = AliTradeStatusUtils.getTradeStatusCode(tradeStatus);

        //如果数据库订单状态不是支付成功，并且远端订单支付状态为空。执行支付成功的方法
        if (order.getState() != OrderStateEnum.订单支付成功() && queryOrderState == OrderStateEnum.订单支付成功()) {
            //TODO 支付成功的后续操作
            applicationEventPublisher.publishEvent(new PaymentSuccessEvent(order));
        }
        //当数据库订单状态与远端订单状态不一致，修改为远端订单状态
        if (!Objects.equals(order.getState(), queryOrderState)) {
            order.setState(queryOrderState);
            orderMapper.update(order, new LambdaQueryWrapper<Order>().eq(Order::getOutTradeNo, out_trade_no));
        }

    }
}
